package com.mulong.mall.service.impl;

import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.mulong.mall.constants.Constants;
import com.mulong.mall.domain.bo.*;
import com.mulong.mall.domain.param.*;
import com.mulong.mall.domain.result.*;
import com.mulong.mall.service.SystemService;
import com.mulong.mall.util.MallRequestContext;
import com.mulong.common.client.AliyunOssClient;
import com.mulong.common.dao.mall.DataDictionaryDao;
import com.mulong.common.dao.mall.EnumDao;
import com.mulong.common.dao.mall.GatewayAccountDao;
import com.mulong.common.domain.pojo.mall.custom.CustomDataDictionary;
import com.mulong.common.domain.pojo.mall.custom.DataDictionaryQuery;
import com.mulong.common.domain.pojo.mall.custom.CustomGatewayAccount;
import com.mulong.common.domain.pojo.mall.custom.GatewayAccountQuery;
import com.mulong.common.enums.GatewayAccountType;
import com.mulong.common.exception.ErrorEnums;
import com.mulong.common.exception.MulongException;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * SystemServiceImpl
 * 
 * @author mulong
 * @data 2021-03-30 21:58:25
 */
@Slf4j
@Service
public class SystemServiceImpl implements SystemService {
    @Autowired
    private GatewayAccountDao gatewayAccountDao;
    @Autowired
    private DataDictionaryDao dataDictionaryDao;
    @Autowired
    private EnumDao enumDao;
    @Autowired
    private AliyunOssClient aliyunOssClient;

    /**
     * 查询网关账号
     * 
     * @author mulong
     */
    @Override
    public GetGatewayAccountByPageResult getGatewayAccountByPage(GetGatewayAccountByPageParam param) {
        GatewayAccountQuery query = new GatewayAccountQuery();
        query.setUsernameKeyword(param.getUsernameKeyword());
        query.setType(param.getType());
        query.setStatus(param.getStatus());
        int pageNo = param.getPageNo() == null ? Constants.DEFAULT_PAGE_NO : param.getPageNo();
        int pageSize = param.getPageSize() == null ? Constants.DEFAULT_PAGE_SIZE : param.getPageSize();
        PageHelper.startPage(pageNo, pageSize, true);
        Page<CustomGatewayAccount> page = (Page<CustomGatewayAccount>) gatewayAccountDao.query(query);
        GetGatewayAccountByPageResult getGatewayAccountByPageResult = new GetGatewayAccountByPageResult(page.getPageNum(), page.getPageSize(), (int)page.getTotal());
        List<CustomGatewayAccount> list = page.getResult();
        if (!CollectionUtils.isEmpty(list)) {
            getGatewayAccountByPageResult.setResult(list.stream().map(GatewayAccount::new).collect(Collectors.toList()));
        }
        return getGatewayAccountByPageResult;
    }

    /**
     * 添加网关账号
     * 
     * @author mulong 
     */
    @Override
    public GatewayAccount addGatewayAccount(GatewayAccount gatewayAccount) {
        gatewayAccount.setId(null);
        CustomGatewayAccount newRecord = gatewayAccount.buildCustomGatewayAccount();
        newRecord = gatewayAccountDao.add(newRecord, MallRequestContext.getUsername());
        return new GatewayAccount(newRecord);
    }

    /**
     * 查询网关账号
     * 
     * @author mulong 
     */
    @Override
    public GatewayAccount getGatewayAccountById(Integer id) {
        CustomGatewayAccount record = gatewayAccountDao.queryById(id);
        if (record == null) {
            throw new MulongException(ErrorEnums.RESOURCE_NOT_EXISTS);
        }
        return new GatewayAccount(record);
    }

    /**
     * 更新网关账号
     * 
     * @author mulong 
     */
    @Override
    public GatewayAccount putGatewayAccountById(Integer id, GatewayAccount gatewayAccount) {
        if (!id.equals(gatewayAccount.getId())) {
            log.error("id mismatch");
            throw new MulongException(ErrorEnums.ILLEGAL_PARAM);
        }
        CustomGatewayAccount record = gatewayAccountDao.queryById(id);
        if (record == null) {
            throw new MulongException(ErrorEnums.RESOURCE_NOT_EXISTS);
        }
        CustomGatewayAccount newRecord = gatewayAccount.buildCustomGatewayAccount();
        record.setUsername(newRecord.getUsername());
        record.setPassword(newRecord.getPassword());
        record.setType(newRecord.getType());
        record.setStatus(newRecord.getStatus());
        record.setRemark(newRecord.getRemark());
        gatewayAccountDao.put(record, MallRequestContext.getUsername());
        return new GatewayAccount(record);
    }

    /**
     * 删除网关账号
     * 
     * @author mulong 
     */
    @Override
    public GatewayAccount deleteGatewayAccountById(Integer id) {
        CustomGatewayAccount record = gatewayAccountDao.queryById(id);
        if (record == null) {
            throw new MulongException(ErrorEnums.RESOURCE_NOT_EXISTS);
        }
        gatewayAccountDao.delete(record, MallRequestContext.getUsername());
        return new GatewayAccount(record);
    }

    /**
     * 查询数据字典
     * 
     * @author mulong
     */
    @Override
    public GetDataDictByPageResult getDataDictByPage(GetDataDictByPageParam param) {
        DataDictionaryQuery query = new DataDictionaryQuery();
        query.setCodeKeyword(param.getCodeKeyword());
        query.setNameKeyword(param.getNameKeyword());
        int pageNo = param.getPageNo() == null ? Constants.DEFAULT_PAGE_NO : param.getPageNo();
        int pageSize = param.getPageSize() == null ? Constants.DEFAULT_PAGE_SIZE : param.getPageSize();
        PageHelper.startPage(pageNo, pageSize, true);
        Page<CustomDataDictionary> page = (Page<CustomDataDictionary>) dataDictionaryDao.query(query);
        GetDataDictByPageResult getDataDictByPageResult = new GetDataDictByPageResult(page.getPageNum(), page.getPageSize(), (int)page.getTotal());
        List<CustomDataDictionary> list = page.getResult();
        if (!CollectionUtils.isEmpty(list)) {
            getDataDictByPageResult.setResult(list.stream().map(DataDict::new).collect(Collectors.toList()));
        }
        return getDataDictByPageResult;
    }

    /**
     * 添加数据字典
     * 
     * @author mulong 
     */
    @Override
    public DataDict addDataDict(DataDict dataDict) {
        dataDict.setId(null);
        CustomDataDictionary newRecord = dataDict.buildCustomDataDictionary();
        newRecord = dataDictionaryDao.add(newRecord, MallRequestContext.getUsername());
        return new DataDict(newRecord);
    }

    /**
     * 查询数据字典
     * 
     * @author mulong 
     */
    @Override
    public DataDict getDataDictById(Integer id) {
        CustomDataDictionary record = dataDictionaryDao.queryById(id);
        if (record == null) {
            throw new MulongException(ErrorEnums.RESOURCE_NOT_EXISTS);
        }
        return new DataDict(record);
    }

    /**
     * 更新数据字典
     * 
     * @author mulong 
     */
    @Override
    public DataDict putDataDictById(Integer id, DataDict dataDict) {
        if (!id.equals(dataDict.getId())) {
            log.error("id mismatch");
            throw new MulongException(ErrorEnums.ILLEGAL_PARAM);
        }
        CustomDataDictionary record = dataDictionaryDao.queryById(id);
        if (record == null) {
            throw new MulongException(ErrorEnums.RESOURCE_NOT_EXISTS);
        }
        CustomDataDictionary newRecord = dataDict.buildCustomDataDictionary();
        record.setCode(dataDict.getCode());
        record.setName(dataDict.getName());
        record.setContent(newRecord.getContent());
        dataDictionaryDao.put(record, MallRequestContext.getUsername());;
        return new DataDict(record);
    }

    /**
     * 删除数据字典
     * 
     * @author mulong 
     */
    @Override
    public DataDict deleteDataDictById(Integer id) {
        CustomDataDictionary record = dataDictionaryDao.queryById(id);
        if (record == null) {
            throw new MulongException(ErrorEnums.RESOURCE_NOT_EXISTS);
        }
        dataDictionaryDao.delete(record, MallRequestContext.getUsername());
        return new DataDict(record);
    }

    /**
     * 获取数据字典
     * 
     * @author mulong
     */
    @Override
    public List<DataDict> fetchDataDicts(List<String> dataDictCodes) {
        if (CollectionUtils.isEmpty(dataDictCodes)) {
            throw new MulongException(ErrorEnums.ILLEGAL_REQUEST);
        }
        List<CustomDataDictionary> records = dataDictionaryDao.queryByCodes(dataDictCodes);
        if (CollectionUtils.isEmpty(records)) {
            return null;
        }
        return records.stream().map(DataDict::new).collect(Collectors.toList());
    }

    /**
     * 获取网关账号权限信息
     * 
     * @author mulong
     */
    @Override
    public GetUserInfoResult getInfo() {
        Integer gatewayAccountId = MallRequestContext.getGatewayAccountId();
        if (gatewayAccountId == null) {
            throw new MulongException(ErrorEnums.ILLEGAL_REQUEST);
        }
        String username = MallRequestContext.getUsername();
        GatewayAccountType gatewayAccountType = MallRequestContext.getUsertype();
        List<String> roles = new ArrayList<>();
        roles.add(gatewayAccountType.getCode());
        GetUserInfoResult getUserInfoResult = new GetUserInfoResult();
        getUserInfoResult.setRoles(roles);
        getUserInfoResult.setIntroduction("I am a " + gatewayAccountType.getName());
        getUserInfoResult.setAvatar("https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
        getUserInfoResult.setName(username);
        return getUserInfoResult;
    }

    /**
     * 更新网关账号密码
     * 
     * @author mulong
     */
    @Override
    public void updatePassword(UpdateGetwayAccountPasswordParam param) {
        Integer gatewayAccountId = MallRequestContext.getGatewayAccountId();
        if (gatewayAccountId == null) {
            throw new MulongException(ErrorEnums.ILLEGAL_REQUEST);
        }
        String username = MallRequestContext.getUsername();        
        if (!param.getUsername().equals(username)) {
            throw new MulongException(ErrorEnums.ILLEGAL_PARAM_TEMPLETE.format("用户名"));
        }
        if (!param.getNewPassword().equals(param.getReNewPassword())) {
            throw new MulongException(ErrorEnums.ILLEGAL_PARAM_TEMPLETE.format("新密码,确认新密码"));
        }
        CustomGatewayAccount gatewayAccount = gatewayAccountDao.queryByUsername(param.getUsername());
        if (gatewayAccount == null) {
            log.error("cannot find gateway user, username {}", username);
            throw new MulongException(ErrorEnums.ILLEGAL_PARAM_TEMPLETE.format("用户名"));
        }
        if (!param.getOldPassword().equals(gatewayAccount.getPassword())) {
            log.error("gateway user password mismatch");
            throw new MulongException(ErrorEnums.ILLEGAL_PARAM_TEMPLETE.format("原密码"));
        }
        gatewayAccount.setPassword(param.getNewPassword());
        gatewayAccountDao.put(gatewayAccount, MallRequestContext.getUsername());
    }

    /**
     * 上传文件
     * 
     * @author mulong
     */
    @Override
    public UploadFileResult uploadFile(MultipartFile file) {
        if (file.isEmpty()) {
            log.error("upload file is empty");
            throw new MulongException(ErrorEnums.UPLOAD_FILE_EMPTY);
        }
        String date = DateUtil.format(new Date(), "yyyyMMdd");
        String key = String.format("file/%s/%s", date, file.getOriginalFilename() + "_" + System.currentTimeMillis());
        try {
            String url = aliyunOssClient.upload(file, key);
            UploadFileResult result = new UploadFileResult();
            result.setUrl(url);
            return result;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new MulongException(ErrorEnums.UPLOAD_FILE_OSS_ERROR);
        }
    }

    /**
     * 上传图片
     * 
     * @author mulong
     */
    @Override
    public UploadImgResult uploadImg(MultipartFile file) {
        if (file.isEmpty()) {
            log.error("upload file is empty");
            throw new MulongException(ErrorEnums.UPLOAD_FILE_EMPTY);
        }
        String date = DateUtil.format(new Date(), "yyyyMMdd");
        String key = String.format("img/%s/%s", date, file.getOriginalFilename() + "_" + System.currentTimeMillis());
        try {
            String url = aliyunOssClient.upload(file, key);
            UploadImgResult result = new UploadImgResult();
            result.setUrl(url);
            return result;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new MulongException(ErrorEnums.UPLOAD_FILE_OSS_ERROR);
        }
    }

    /**
     * 获取枚举
     * 
     * @author mulong
     */
    @Override
    public List<SystemEnum> fetchEnum(List<String> enumCodes) {
        Map<String, List<?>> map = enumDao.getEnumByCode(enumCodes);
        List<SystemEnum> result = new ArrayList<>();
        for (Entry<String, List<?>> entry : map.entrySet()) {
            String key = entry.getKey();
            List<?> value = entry.getValue();
            SystemEnum systemEnum = new SystemEnum();
            systemEnum.setCode(key);
            systemEnum.setOptions(value);
            result.add(systemEnum);
        }
        return result;
    }

    /**
     * EnumBrand
     * 
     * @author mulong
     */
    @Override
    public List<EnumBrand> getEnumBrand() {
        List<com.mulong.common.domain.pojo.mall.Brand> all = enumDao.getAllBrand();
        if (CollectionUtils.isEmpty(all)) {
            return null;
        }
        all.sort(new Comparator<com.mulong.common.domain.pojo.mall.Brand>() {
            @Override
            public int compare(com.mulong.common.domain.pojo.mall.Brand o1, com.mulong.common.domain.pojo.mall.Brand o2) {
                return o1.getBrandOrder().compareTo(o2.getBrandOrder());
            }
        });
        return all.stream().map(EnumBrand::new).collect(Collectors.toList());
    }

    /**
     * EnumDeliveryType
     * 
     * @author mulong
     */
    @Override
    public List<EnumDeliveryType> getEnumDeliveryType() {
        List<com.mulong.common.domain.pojo.mall.DeliveryType> all = enumDao.getAllDeliveryType();
        if (CollectionUtils.isEmpty(all)) {
            return null;
        }
        all.sort(new Comparator<com.mulong.common.domain.pojo.mall.DeliveryType>() {
            @Override
            public int compare(com.mulong.common.domain.pojo.mall.DeliveryType o1, com.mulong.common.domain.pojo.mall.DeliveryType o2) {
                return o1.getDeliveryTypeOrder().compareTo(o2.getDeliveryTypeOrder());
            }
        });
        return all.stream().map(EnumDeliveryType::new).collect(Collectors.toList());
    }

    /**
     * EnumSupplierChannel
     * 
     * @author mulong
     */
    @Override
    public List<EnumSupplierChannel> getEnumSupplierChannel() {
        List<com.mulong.common.domain.pojo.mall.SupplierChannel> all = enumDao.getAllSupplierChannel();
        if (CollectionUtils.isEmpty(all)) {
            return null;
        }
        return all.stream().map(EnumSupplierChannel::new).collect(Collectors.toList());
    }

}
